# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/topics/item-pipeline.html

import re
import psycopg2
import sys
import datetime

from scrapy.conf import settings
#from scrapy.exceptions import DropItem


class CotizacionesPipeline(object):

    hoy = datetime.datetime.today()
    fecha = '%s-%s-%s' % (hoy.year, hoy.month, hoy.day)

    conn_string = "host='%s' port='%s' dbname='%s' user='%s' password='%s'"\
                  % (settings['POSTGRESQL_HOST'],
                     settings['POSTGRESQL_PORT'],
                     settings['POSTGRESQL_DB'],
                     settings['POSTGRESQL_USER'],
                     settings['POSTGRESQL_PASSWORD'])

    def process_item(self, item, spider):

        cotizaciones = {}

        try:
            # Connect to an existing database
            conn = psycopg2.connect(self.conn_string)
            # Open a cursor to perform database operations
            cursor = conn.cursor()
        except psycopg2.Error as e:
            text = '\nHa fallado la conexion a la base de datos\n\n%s' % e
            subject = "Script de cotizaciones: Error de psycopg2"
            self.email_notifier(text, subject)
            sys.exit()

        def query_select(moneda, tipo_valor):
            query = """SELECT %(tipo)s FROM %(table)s where moneda='%(moneda)s' and fecha=(SELECT max(fecha)
                    from %(table)s)""" % {'table': settings['POSTGRESQL_TABLE'], 'moneda': moneda, 'tipo': tipo_valor}
            return query

        if spider.name == 'BROU':
            # Process BROU Spider
            for field in item:
                if item[field]:
                    clean_string_value = re.sub(',', '.', re.sub('\s', '', item[field][0]))
                    clean_float_value = round(float(clean_string_value), 2)
                    item[field] = clean_float_value
                    if 'dolar_compra' in field:
                        cotizaciones['dolar_compra'] = item[field]
                    elif 'dolar_venta' in field:
                        cotizaciones['dolar_venta'] = item[field]
                    elif 'euro_compra' in field:
                        cotizaciones['euro_compra'] = item[field]
                    elif 'euro_venta' in field:
                        cotizaciones['euro_venta'] = item[field]
            if not cotizaciones:
                # Si no hay valores se toman los ultimos que hay en la DB y se notifica por email
                try:
                    cursor.execute(query_select('USD', 'compra'))
                    cotizaciones['dolar_compra'] = cursor.fetchall()[0]
                    cursor.execute(query_select('USD', 'venta'))
                    cotizaciones['dolar_venta'] = cursor.fetchall()[0]
                    cursor.execute(query_select('EUR', 'compra'))
                    cotizaciones['euro_compra'] = cursor.fetchall()[0]
                    cursor.execute(query_select('EUR', 'venta'))
                    cotizaciones['euro_venta'] = cursor.fetchall()[0]
                except psycopg2.Error as e:
                    text = '\nHa fallado la conexion a la base de datos\n\n%s' % e
                    subject = "Script de cotizaciones: Error de psycopg2"
                    self.email_notifier(text, subject)
                    sys.exit()

                text = "No se pudieron obtener valores de cotizaciones de BROU"
                subject = 'Script de cotizaciones: Errores de datos.'
                self.email_notifier(text, subject)

        elif spider.name == 'BCU':
            # Process BCU Spider
            for field in item:
                if item[field]:
                    clean_string_value = re.sub(',', '.', re.sub('\s', '', item[field][0]))
                    clean_float_value = round(float(clean_string_value), 3)
                    item[field] = clean_float_value
                    if 'dolar_interbancario' in field:
                        cotizaciones['dolar_interbancario'] = item[field]
                    elif 'euro_interbancario' in field:
                        cotizaciones['euro_interbancario'] = item[field]
            if not cotizaciones:
                try:
                    # Si no hay valores se toman los ultimos que hay en la DB y se notifica por email
                    cursor.execute(query_select('USD', 'interbancario'))
                    cotizaciones['dolar_interbancario'] = cursor.fetchall()[0]
                    cursor.execute(query_select('USD', 'interbancario'))
                    cotizaciones['euro_interbancario'] = cursor.fetchall()[0]
                except psycopg2.Error as e:
                    text = '\nHa fallado la conexion a la base de datos\n\n%s' % e
                    subject = "Script de cotizaciones: Error de psycopg2"
                    self.email_notifier(text, subject)
                    sys.exit()

                text = "No se pudieron obtener valores de cotizaciones de BCU"
                subject = 'Script de cotizaciones: Errores de datos.'
                self.email_notifier(text, subject)

        # Si hay cotizaciones verificar que no falten valores y enviar a la DB
        if all(k in cotizaciones for k in ("dolar_compra", "dolar_venta", "euro_compra", "euro_venta")):
            self.sql_insert_update(cotizaciones, 'compra', 'venta')
        elif all(k in cotizaciones for k in ("dolar_interbancario", "euro_interbancario")):
            self.sql_insert_update(cotizaciones, 'interbancario')
        else:
            text = "No se pudieron obtener todos los valores de cotizaciones\n\n Datos:\n\n%s" % cotizaciones
            subject = 'Script de cotizaciones: Errores de datos.'
            self.email_notifier(text, subject)
        return item

    def sql_insert_update(self, cotizaciones, *tipos_valores):

        def query_insert(moneda):
            query = """INSERT INTO %(table)s (fecha, moneda, %(tipos_valores)s) SELECT %%s, '%(moneda)s', %(valores)s
                WHERE NOT EXISTS
                (SELECT fecha, moneda FROM %(table)s WHERE fecha=%%s AND moneda = '%(moneda)s');""" %\
                {'table': settings['POSTGRESQL_TABLE'], 'moneda': moneda,
                 'tipos_valores': ', '.join(tipos_valores), 'valores': ', '.join('%s' for i in tipos_valores)}
            return query

        def query_update(moneda):
            query = """UPDATE %(table)s SET %(tipos_valores)s
                WHERE fecha = %%s AND moneda = '%(moneda)s';""" %\
                {'table': settings['POSTGRESQL_TABLE'], 'moneda': moneda,
                 'tipos_valores': ', '.join(i + ' = %s' for i in tipos_valores)}
            return query

        try:
            # Connect to an existing database
            conn = psycopg2.connect(self.conn_string)
            # Open a cursor to perform database operations
            cursor = conn.cursor()
        except psycopg2.Error as e:
            text = '\nHa fallado la conexion a la base de datos\n\n%s' % e
            subject = "Script de cotizaciones: Error de psycopg2"
            self.email_notifier(text, subject)
            sys.exit()

        if not 'interbancario' in tipos_valores:
                # Insertar sino existen o actualizar si existen (por cada moneda)
                # Dolar compra/venta
                cursor.execute(query_insert('USD'), (self.fecha, cotizaciones['dolar_compra'],
                    cotizaciones['dolar_venta'], self.fecha))
                cursor.execute(query_update('USD'),
                    (cotizaciones['dolar_compra'], cotizaciones['dolar_venta'], self.fecha))

                # Euro compra/venta
                cursor.execute(query_insert('EUR'), (self.fecha, cotizaciones['euro_compra'],
                    cotizaciones['euro_venta'], self.fecha))
                cursor.execute(query_update('EUR'),
                    (cotizaciones['euro_compra'], cotizaciones['euro_venta'], self.fecha))
        else:
                # Insertar sino existen o actualizar si existen (por cada moneda)
                # Dolar Interbancario
                cursor.execute(query_insert('USD'), (self.fecha, cotizaciones['dolar_interbancario'], self.fecha))
                cursor.execute(query_update('USD'), (cotizaciones['dolar_interbancario'], self.fecha))
                # Euro Interbancario
                cursor.execute(query_insert('EUR'), (self.fecha, cotizaciones['euro_interbancario'], self.fecha))
                cursor.execute(query_update('EUR'), (cotizaciones['euro_interbancario'], self.fecha))
        try:
            # Make the changes to the database persistent
            conn.commit()
            # Close communication with the database
            cursor.close()
            conn.close()
        except psycopg2.Error as e:
            text = '\nHa fallado la conexion a la base de datos\n\n%s' % e
            subject = "Script de cotizaciones: Error de psycopg2"
            self.email_notifier(text, subject)
            sys.exit()

    @staticmethod
    def email_notifier(text, subject):
        """
        Send email notification with 'text' in body.

        """
        import smtplib
        from email.mime.text import MIMEText

        msg = MIMEText(text)
        msg['Subject'] = '[Cotizaciones Elremate]' + subject
        msg['From'] = 'elmonkeylp@gmail.com'
        msg['To'] = 'elmonkeylp@gmail.com'
        s = smtplib.SMTP('localhost')
        s.sendmail('', ['elmonkeylp@gmail.com'], msg.as_string())
        s.quit()
